﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Xml;
using System.Threading;
using GoTextPalm.Core.Localization;
using GoTextPalm.Core;

namespace GoTextPalm.Gui
{
    public partial class FromRepositoryForm : LocalizedForm
    {
        private Logic logic;

        public FromRepositoryForm()
        {
            logic = new Logic();
            logic.LoadProcedureEndedEvent += new Logic.LoadProcedureEndedHandler(Logic_LoadProcedureEnded);
            logic.ErrorCaused += new Logic.ErrorCausedHandler(Logic_ErrorCaused);
            logic.StatusTextChangedEvent += new Logic.StatusTextChangedHandler(Logic_StatusTextChanged);
            InitializeComponent();
            header.Text = "Services Catalog";
            AddMenusToDictionary();
            UpdateResources();
        }

        protected override void AddMenusToDictionary()
        {
            AddMenuToDictionary(mnuChoose, "mnuChoose");
        }

        private void FromRepositoryForm_Load(object sender, EventArgs e)
        {
            mnuChoose.Enabled = lstSrvs.Enabled = lstTags.Enabled = lblTags.Enabled = lblSrvs.Enabled = false;
            new Thread(new ThreadStart(logic.LoadProcedure)).Start();
        }

        private int currSelected = 0;

        private void lstTags_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            if (e.NewValue == CheckState.Checked)
                currSelected++;
            else
                currSelected--;
            lstSrvs.Items.Clear();
            if (currSelected == 0)
                lstSrvs.Items.Add(new ListViewItem(Utility.Tr("FromRepositoryForm_select", "Choose at least a filter tag")));
            else
            {
                List<ServiceCandidate> scl = null;
                int lviIndex = -1;
                if (e.NewValue == CheckState.Checked)
                {
                    scl = new List<ServiceCandidate>((List<ServiceCandidate>)lstTags.Items[e.Index].Tag);
                    lviIndex = e.Index;
                }
                else
                {
                    foreach (ListViewItem lvi in lstTags.Items)
                        if (lvi.Checked)
                        {
                            scl = new List<ServiceCandidate>((List<ServiceCandidate>)lvi.Tag);
                            lviIndex = lvi.Index;
                            break;
                        }
                }
                List<ServiceCandidate> rem = new List<ServiceCandidate>();
                foreach (ListViewItem lvi in lstTags.Items)
                {
                    if (lvi.Index == e.Index)
                        continue;
                    if (lvi.Checked && lvi.Index != lviIndex)
                    {
                        foreach (ServiceCandidate sc in scl)
                            if (!sc.Tags.Contains(lvi.Text))
                                rem.Add(sc);
                        foreach (ServiceCandidate sc in rem)
                            scl.Remove(sc);
                        rem.Clear();
                    }
                }
                if (scl.Count == 0)
                    lstSrvs.Items.Add(new ListViewItem(Utility.Tr("FromRepositoryForm_notfound", "No service found with these tags")));
                else
                    foreach (ServiceCandidate sc in scl)
                    {
                        ListViewItem lvi = new ListViewItem(sc.Name);
                        lvi.Tag = sc;
                        lstSrvs.Items.Add(lvi);
                    }
            }
            lstSrvs.Refresh();
        }

        private void lstSrvs_SelectedIndexChanged(object sender, EventArgs e)
        {
            mnuChoose.Enabled = lstSrvs.SelectedIndices.Count == 1
                && lstSrvs.Items[lstSrvs.SelectedIndices[0]].Tag != null;
        }

        private bool modified;

        private void mnuChoose_Click(object sender, EventArgs e)
        {
            if (new NewServiceForm((ServiceCandidate)lstSrvs.Items[lstSrvs.SelectedIndices[0]].Tag).ShowDialog() == DialogResult.OK)
                modified = true;
        }

        private void lstSrvs_ItemActivate(object sender, EventArgs e)
        {
            mnuChoose_Click(sender, e);
        }

        private void FromRepositoryForm_Closing(object sender, CancelEventArgs e)
        {
            DialogResult = modified ? DialogResult.OK : DialogResult.Cancel;
        }

        void Logic_LoadProcedureEnded(Dictionary<String, List<ServiceCandidate>> dict)
        {
            if (InvokeRequired)
            {
                Logic.LoadProcedureEndedHandler func = Logic_LoadProcedureEnded;
                Invoke(func, dict);
                return;
            }
            mnuChoose.Enabled = lstSrvs.Enabled = lstTags.Enabled = lblTags.Enabled = lblSrvs.Enabled = true;
            stsBar.Visible = stsBar.ProgressStarted = false;
            lstTags.Items.Clear();
            foreach (String key in dict.Keys)
            {
                ListViewItem lvi = new ListViewItem(key);
                lvi.Tag = dict[key];
                lstTags.Items.Add(lvi);
            }
            lstTags.Refresh();
            lstSrvs.Items.Clear();
            lstSrvs.Items.Add(new ListViewItem(Utility.Tr("FromRepositoryForm_select", "Choose at least a filter tag")));
            lstSrvs.Refresh();
        }

        void Logic_ErrorCaused(String text)
        {
            if (InvokeRequired)
            {
                Logic.ErrorCausedHandler func = Logic_ErrorCaused;
                Invoke(func, text);
                return;
            }
            mnuChoose.Enabled = lstSrvs.Enabled = lstTags.Enabled = lblTags.Enabled = lblSrvs.Enabled = true;
            stsBar.Visible = stsBar.ProgressStarted = false;
            MessageBox.Show(text, header.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            Close();
        }

        void Logic_StatusTextChanged(String text)
        {
            if (InvokeRequired)
            {
                Logic.StatusTextChangedHandler func = Logic_StatusTextChanged;
                Invoke(func, text);
                return;
            }
            if (!stsBar.Visible)
                stsBar.Visible = stsBar.ProgressStarted = true;
            stsBar.Text = text;
        }

        private class Logic
        {
            public delegate void LoadProcedureEndedHandler(Dictionary<String, List<ServiceCandidate>> dict);
            public event LoadProcedureEndedHandler LoadProcedureEndedEvent;

            public delegate void StatusTextChangedHandler(String text);
            public event StatusTextChangedHandler StatusTextChangedEvent;

            public delegate void ErrorCausedHandler(String text);
            public event ErrorCausedHandler ErrorCaused;

            public void LoadProcedure()
            {
                try
                {
                    FireStatusTextChanged(Utility.Tr("FromRepositoryForm_sts1", "Loading Catalog ..."));
                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Constants.REPOSITORY_URL);
                    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                    XmlReader reader = XmlReader.Create(response.GetResponseStream());
                    XmlDocument doc = new XmlDocument();
                    doc.Load(reader);
                    foreach (XmlNode srvsNode in doc.ChildNodes)
                        if (srvsNode.Name == "services")
                        {
                            XmlNodeList list = srvsNode.ChildNodes;
                            Dictionary<String, List<ServiceCandidate>> tagsWithSrvs = new Dictionary<string, List<ServiceCandidate>>();
                            foreach (XmlNode node in list)
                                if (node.Name == "service")
                                {
                                    ServiceCandidate sc = new ServiceCandidate { Name = node.Attributes["name"].Value, URL = node.Attributes["url"].Value };
                                    XmlNodeList tags = node.ChildNodes;
                                    foreach (XmlNode tag in tags)
                                        if (tag.Name == "tag")
                                            sc.Tags.Add(tag.InnerText);
                                    foreach (String tag in sc.Tags)
                                    {
                                        if (!tagsWithSrvs.ContainsKey(tag))
                                            tagsWithSrvs[tag] = new List<ServiceCandidate>();
                                        tagsWithSrvs[tag].Add(sc);
                                    }
                                }
                            FireLoadProcedureEnded(tagsWithSrvs);
                        }
                }
                catch (WebException e)
                {
                    FireErrorCaused(Utility.Tr("FromRepositoryForm_webex", "Cannot connect to the catalog. Maybe the connection is absent"));
                }
                catch (XmlException e)
                {
                    FireErrorCaused(Utility.Tr("FromRepositoryForm_xmlex", "Cannot read catalog response. Catalog Response is incorrect"));
                }
            }

            private void FireLoadProcedureEnded(Dictionary<String, List<ServiceCandidate>> dict)
            {
                if (LoadProcedureEndedEvent != null)
                    LoadProcedureEndedEvent(dict);
            }

            private void FireStatusTextChanged(String text)
            {
                if (StatusTextChangedEvent != null)
                    StatusTextChangedEvent(text);
            }

            private void FireErrorCaused(String text)
            {
                if (ErrorCaused != null)
                    ErrorCaused(text);
            }
        }
    }
}